#include "Fragment.h"
#include "FragmentationDemo.h"

#include <assert.h>
#include <iostream>
#include <GL\glut.h>

Fragment::Fragment(btRigidBody* rigidBody, btMotionState* motionState, const ConvexHull& hull, float volume, float materialDensity) 
{
	m_pRigidBody = rigidBody;
	m_pMotionState = (btDefaultMotionState*)motionState;
	m_materialDensity = materialDensity;

	m_convexHull = hull;
	m_volume = volume;
	m_fractured = false;
}

void Fragment::Collided(btManifoldPoint& contact)
{
	//contact.

	int contactTime = contact.getLifeTime();

	float force = contact.getAppliedImpulse();
	
	//float volumeComp = m_halfExtents.Length();
	int breakFactor = rand() % 100;

	if(force > (m_volume*6) && (breakFactor > 90) && contactTime < 2)
	{
		//Subsequent fracturing disabled as it causes physics instability
		//Shatter();
		//m_fractured = true;
	}
	
}

void Fragment::Shatter()
{
	
	//btVector3 bbmax(m_halfExtents.X, m_halfExtents.Y, m_halfExtents.Z);
	//btVector3 bbmin = -bbmax;
	btVector3 bbt = m_pRigidBody->getWorldTransform().getOrigin();
	//btVector3 bbt(m_pos.X, m_pos.Y, m_pos.Z);
	//btVector3 diff = bbmax - bbmin;
	btAlignedObjectArray<btVector3> points;
	btVector3 point;

	assert(m_pRigidBody);
	btQuaternion bbq = m_pRigidBody->getOrientation();

	
	int fragments = 4;


	for (unsigned int i=0; i < fragments; i++) 
	{

		// Place points within box area (points are in world coordinates)
		//point = quatRotate(bbq, btVector3(btScalar(rand() / btScalar(RAND_MAX)) * diff.x() -diff.x()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.y() -diff.y()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.z() -diff.z()/2.)) + bbt;
		btVector3 voroPoint((float)((rand() % fragments) / 10), 0, (float)((rand() % fragments) / 10));
		
		point = quatRotate(bbq, voroPoint + bbt);
		points.push_back(point);
	}
	btAlignedObjectArray<btVector3> verts;
	std::vector<ConvexHull::Face>* faces = m_convexHull.GetFaces();
	verts.reserve(faces->size() * 8 * 3);
	std::vector<ConvexHull::Face>::iterator it = faces->begin();
	std::vector<ConvexHull::Face>::iterator end = faces->end();
	
	for( ; it != end; ++it)
	{
		int tris = (*it).m_tris.size();
		for( int j = 0;  j < tris; j++)
		{
			verts.push_back((*it).m_tris[j].v0);
			verts.push_back((*it).m_tris[j].v1);
			verts.push_back((*it).m_tris[j].v2);
		}
	}

	voronoiConvexHullShatter(points, verts, bbq, bbt, m_materialDensity, m_pRigidBody->getLinearVelocity());
	//voronoiBBShatter(points, bbmin, bbmax, bbq, bbt, m_materialDensity, m_pRigidBody->getLinearVelocity());
	TheFragmentationDemo::Instance()->AddOrRemoveRigidBody(false, m_pRigidBody);
	//m_fractured = true;
	
}

void Fragment::Update()
{
	
}

void Fragment::Draw()
{
	//m_pRigidBody->getCollisionShape();

	if(!m_fractured)
	{

		glPushMatrix();

		btTransform btTrans;
		m_pMotionState->getWorldTransform(btTrans);
		btTrans.getOpenGLMatrix(m_mat.m_matrix);
		m_mat.MultiOpenGL();

		glDisable(GL_TEXTURE_2D);
		//glEnable(GL_COLOR_MATERIAL);

		//glColor3f(0,0,1);
		m_convexHull.Draw();

		//glDisable(GL_COLOR_MATERIAL);
		glEnable(GL_TEXTURE_2D);

		glPopMatrix();
	}
	else
	{
		std::vector<Fragment*>::iterator it = m_fragments.begin();
		std::vector<Fragment*>::iterator end = m_fragments.end();
		for( ; it != end; ++it)
		{
			(*it)->Draw();
		}
	}


}